package com.example.score.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.score.common.ServiceException;
import com.example.score.dto.*;
import com.example.score.dto.StudentInfo;
import com.example.score.entity.*;
import com.example.score.mapper.*;
import com.example.score.mq.producer.ErrorQuestionProducer;
import com.example.score.utils.CalculateQuestionNumUtil;
import com.example.score.utils.GZipUtils;
import com.example.score.utils.WxUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import static io.netty.handler.ssl.OpenSslCertificateCompressionConfig.AlgorithmMode.Compress;

@Slf4j
@Service
public class ExamService {

    @Autowired
    private ExamBaseMapper examBaseMapper;
    @Autowired
    private ExamDetailMapper examDetailMapper;
    @Autowired
    private GradeInfoMapper gradeInfoMapper;
    @Autowired
    private ClassInfoMapper classInfoMapper;
    @Autowired
    private QuestionInfoMapper questionInfoMapper;
    @Autowired
    private StudentSubmitMapper studentSubmitMapper;
    @Autowired
    private QuestionScoreMapper questionScoreMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${api.base-yj-url}")
    private String baseUrl;

    @Value("${oms.studentInfo_url}")
    private String studentInfoUrl;

    @Value("${wx.page_path}")
    private String wxPagePath;

    @Resource
    private ErrorQuestionProducer errorQuestionProducer;

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final String REPORT_QUEUE_KEY = "exam:report:queue";

    @Transactional
    public void checkExamBaseInfo(ExamBaseDTO examBaseDTO) {
        //判断状态是否删除
        Boolean isrepublish = examBaseDTO.getIsrepublish();
        if (isrepublish) {

            ExamDetail examDetail = examDetailMapper.selectByExamId(examBaseDTO.getExamId());
            if (ObjectUtils.isEmpty(examDetail)) {
                return;
            }
            List<ClassInfo> unSyncedClasses = classInfoMapper.selectByExamDetailId(examDetail.getId());
            long count = unSyncedClasses.stream().filter(a -> a.getStatus() == 2).count();
            //允许删除
            if (count != 0 && unSyncedClasses.size() == count) {
                examBaseMapper.deleteByExamId(examBaseDTO.getExamId());

                examDetailMapper.deleteById(examDetail.getId());

                List<Long> classIds = unSyncedClasses.stream().map(ClassInfo::getId).collect(Collectors.toList());
                classInfoMapper.deleteBatchIds(classIds);

                QueryWrapper<GradeInfo> gradeInfoQueryWrapper = new QueryWrapper<>();
                gradeInfoQueryWrapper.eq("exam_detail_id", examDetail.getId());
                gradeInfoMapper.delete(gradeInfoQueryWrapper);

                QueryWrapper<QuestionInfo> questionInfoQueryWrapper = new QueryWrapper<>();
                questionInfoQueryWrapper.eq("exam_detail_id", examDetail.getId());
                questionInfoMapper.delete(questionInfoQueryWrapper);

                QueryWrapper<StudentSubmit> studentSubmitQueryWrapper = new QueryWrapper<>();
                studentSubmitQueryWrapper.eq("exam_detail_id", examDetail.getId());
                studentSubmitMapper.delete(studentSubmitQueryWrapper);

                questionScoreMapper.deleteByExamDetailId(examDetail.getId());
            } else {
                throw new ServiceException("任务执行中,请稍后重试");
            }
        }
    }

    @Transactional
    public Long saveExamBaseInfo(ExamBaseDTO examBaseDTO) {
        try {
            log.info("开始保存考试基础信息: {}", examBaseDTO.getExamName());

            // 1. 转换并保存考试基本信息
            ExamBase examBase = new ExamBase();
            examBase.setExamId(examBaseDTO.getExamId());
            examBase.setExamName(examBaseDTO.getExamName());
            examBase.setStartTime(LocalDateTime.parse(examBaseDTO.getStartTime(), formatter));
            examBase.setEndTime(LocalDateTime.parse(examBaseDTO.getEndTime(), formatter));
            examBase.setExamType(examBaseDTO.getExamType());
            examBase.setSchoolId(examBaseDTO.getSchoolId());
            examBase.setSchoolOmsId(examBaseDTO.getSchoolOmsId());
            examBase.setSchoolName(examBaseDTO.getSchoolName());
            examBase.setStageId(examBaseDTO.getStageId());
            examBase.setStageOmsId(examBaseDTO.getStageOmsId());
            examBase.setStage(examBaseDTO.getStage());
            examBase.setStatus(0);
            examBaseMapper.insert(examBase);

            // 2. 创建考试详情
            ExamDetail examDetail = new ExamDetail();
            examDetail.setGradeId(examBaseDTO.getChidrenGrade().get(0).getGradeId());
            examDetail.setGradeOmsId(examBaseDTO.getChidrenGrade().get(0).getGradeOmsId());
            examDetail.setSchoolNumber(examBaseDTO.getSchoolNumber());
            examDetail.setExamId(examBase.getExamId());
            examDetail.setSubjectOnlyid(examBaseDTO.getSubjectOnlyid());
            examDetail.setSubjectId(examBaseDTO.getSubjectId());
            examDetail.setSubjectName(examBaseDTO.getSubjectName());
            examDetail.setStatus(examBaseDTO.getStatus() != null ? examBaseDTO.getStatus() : 0);
            examDetailMapper.insert(examDetail);
            // 3. 批量保存年级信息
            if (examBaseDTO.getChidrenGrade() != null) {
                List<ClassInfo> allClassInfos = new ArrayList<>();

                for (ExamBaseDTO.GradeDTO gradeDTO : examBaseDTO.getChidrenGrade()) {
                    GradeInfo grade = new GradeInfo();
                    grade.setExamDetailId(examDetail.getId());
                    grade.setGradeId(gradeDTO.getGradeId());
                    grade.setGradeOmsId(gradeDTO.getGradeOmsId());
                    grade.setGradeName(gradeDTO.getGradeName());
                    grade.setSchoolId(examBaseDTO.getSchoolId());
                    gradeInfoMapper.insert(grade);
                    // 4. 收集班级信息
                    if (gradeDTO.getChidrenClass() != null) {
                        for (ExamBaseDTO.ClassDTO classDTO : gradeDTO.getChidrenClass()) {
                            ClassInfo classInfo = new ClassInfo();
                            classInfo.setExamDetailId(examDetail.getId());
                            classInfo.setGradeInfoId(grade.getId());
                            classInfo.setClassId(classDTO.getClassId());
                            classInfo.setClassOmsId(classDTO.getClassOmsId());
                            classInfo.setClassName(classDTO.getClassName());
                            classInfo.setStudentCount(classDTO.getStudentCount());
                            classInfo.setStudentSubmitCount(classDTO.getStudentSubmitCount());
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                            LocalDateTime dateTime = LocalDateTime.parse(classDTO.getClassFirstpushscoreTime(), formatter);
                            classInfo.setClassFirstpushscoreTime(dateTime);
                            classInfo.setStatus(0);
                            allClassInfos.add(classInfo);
                        }
                    }
                }

                // 批量插入班级信息
                if (!allClassInfos.isEmpty()) {
                    classInfoMapper.insertBatch(allClassInfos);
                }
            }

            // 5. 收集并计算题目信息
            double totalScore = 0.0;
            List<QuestionInfo> allQuestions = new ArrayList<>();
            if (examBaseDTO.getQuesInfos() != null) {
                for (ExamBaseDTO.QuestionDTO questionDTO : examBaseDTO.getQuesInfos()) {
                    totalScore += collectQuestions(questionDTO, examDetail.getId(), null, allQuestions);
                }
            }

            // 批量插入题目信息
            if (!allQuestions.isEmpty()) {
                questionInfoMapper.insertBatch(allQuestions);
            }

            // 更新考试总分
            examDetail.setFullScore((int) totalScore);
            examDetailMapper.updateById(examDetail);

            log.info("考试基础信息保存完成: {}", examBaseDTO.getExamName());
            return examBase.getExamId();

        } catch (Exception e) {
            log.error("保存考试基础信息失败: {}", e.getMessage(), e);
            throw new RuntimeException("保存考试基础信息失败", e);
        }
    }

    private double collectQuestions(ExamBaseDTO.QuestionDTO questionDTO, Long examDetailId, Long parentId, List<QuestionInfo> questions) {
        QuestionInfo question = new QuestionInfo();
        question.setExamDetailId(examDetailId);
        question.setQuestionId(questionDTO.getQuestionId());
        question.setQuestionNum(questionDTO.getQuestionNum());
        question.setQuestionAlias(questionDTO.getQuestionAlias());
        question.setQuestionType(questionDTO.getQuestionType());
        question.setQuestionTypeName(questionDTO.getQuestionTypeName());
        question.setQuestionAnswer(questionDTO.getQuestionAnswer());
        question.setQuestionScore(questionDTO.getQuestionScore());
        question.setParentId(parentId);
        question.setIsSubjectiveItem(questionDTO.getIsSubjectiveItem());
        question.setQuestionBankId(questionDTO.getQuestionBankId());
        question.setX(questionDTO.getX());
        question.setY(questionDTO.getY());
        question.setW(questionDTO.getW());
        question.setH(questionDTO.getH());
        question.setPage(questionDTO.getPage());
        questions.add(question);

        double totalScore = questionDTO.getQuestionScore() != null ? questionDTO.getQuestionScore() : 0.0;

        // 递归处理子题目
        if (questionDTO.getChidren() != null) {
            for (ExamBaseDTO.QuestionDTO childQuestion : questionDTO.getChidren()) {
                totalScore += collectQuestions(childQuestion, examDetailId, question.getId(), questions);
            }
        }

        return totalScore;
    }


    //@Scheduled(fixedDelay = 30000) // 30秒执行一次
    @Transactional
    public List<StudentSubmit> syncExamDetails(ExamBaseDTO examBase) {
        try {
            log.info("开始同步考试详情数据");

            // 1. 查询未同步的班级信息
            List<ClassInfo> unSyncedClasses = classInfoMapper.selectUnsyncedClasses();
            if (unSyncedClasses.isEmpty()) {
                log.info("没有需要同步的班级数据");
                return null;
            }
            List<StudentSubmit> studentSubmitList = new ArrayList<>();
            for (ClassInfo classInfo : unSyncedClasses) {
                try {
                    // 4. 更新班级同步状态
                    classInfo.setStatus(1); // 修改为同步中
                    classInfoMapper.updateById(classInfo);
                    // 2. 获取考试详情
                    ExamDetail examDetail = examDetailMapper.selectById(classInfo.getExamDetailId());
                    if (examDetail == null) {
                        log.error("未找到考试详情数据: examDetailId={}", classInfo.getExamDetailId());
                        continue;
                    }

                    // 3. 调用发布成绩接口
                    studentSubmitList.addAll(publishScore(examDetail.getSubjectId(), classInfo, examBase));
                    classInfo.setStatus(2); // 已同步
                    classInfoMapper.updateById(classInfo);
                    log.info("班级数据同步成功: classId={}, examDetailId={}",
                            classInfo.getClassId(), classInfo.getExamDetailId());

                    // 将考试详情ID加入Redis队列，等待生成报表
                    redisTemplate.opsForList().rightPush(REPORT_QUEUE_KEY, classInfo.getExamDetailId());
                    log.info("已将考试详情ID加入报表队列: examDetailId={}", classInfo.getExamDetailId());
                } catch (Exception e) {
                    log.error("同步班级数据失败: classId={}, error={}",
                            classInfo.getClassId(), e.getMessage(), e);
                }
            }
            log.info("考试详情数据同步完成");
            return studentSubmitList;
        } catch (Exception e) {
            log.error("同步考试详情数据失败: {}", e.getMessage(), e);
            throw new RuntimeException("同步考试详情数据失败", e);
        }
    }


    public List<StudentSubmit> publishScore(Long subjectId, ClassInfo classInfo, ExamBaseDTO examBase) {
        try {
            String url = baseUrl + "/api/score/publishscore";

            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("examCourseId", subjectId);
            params.put("classId", classInfo.getClassId());

            // 构建查询字符串
            StringBuilder queryString = new StringBuilder();
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (queryString.length() > 0) {
                    queryString.append("&");
                }
                String key = entry.getKey();
                String value = entry.getValue().toString();
                queryString.append(URLEncoder.encode(key, StandardCharsets.UTF_8.toString()))
                        .append("=")
                        .append(URLEncoder.encode(value, StandardCharsets.UTF_8.toString()));
            }

            url = url + "?" + queryString;

            // 发送 GET 请求
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            String result = response.getBody();
            List<ExamDetailDTO.StudentDTO> studentDTOList = new ArrayList<>();
            if (response.getStatusCode() == HttpStatus.OK && result != null) {
                ObjectMapper mapper = new ObjectMapper();
                AjaxResult ajaxResult = mapper.readValue(result, AjaxResult.class);
                Object data = ajaxResult.get("data");
                ExamDetailDTO examDetailDTO = mapper.readValue(JSON.toJSONString(data), ExamDetailDTO.class);

                // 处理每个学生的数据
                List<StudentSubmit> studentSubmits = new ArrayList<>();
                if (examDetailDTO != null && examDetailDTO.getStudents() != null && !examDetailDTO.getStudents().isEmpty()) {
                    List<QuestionScore> allQuestionScores = new ArrayList<>();
                    studentDTOList = examDetailDTO.getStudents();
                    for (ExamDetailDTO.StudentDTO studentDTO : examDetailDTO.getStudents()) {
                        // 1. 收集学生提交记录
                        StudentSubmit studentSubmit = new StudentSubmit();
                        studentSubmit.setClassInfoId(classInfo.getId());
                        studentSubmit.setClassId(classInfo.getClassId());
                        studentSubmit.setStudentId(studentDTO.getStudentId());
                        studentSubmit.setStudentOmsId(studentDTO.getStudentOmsId());
                        studentSubmit.setStudentName(studentDTO.getStudentName());
                        if (!ObjectUtils.isEmpty(examBase) && !ObjectUtils.isEmpty(examBase.getSchoolNumber())) {
                            studentSubmit.setStudentNum(examBase.getSchoolNumber() + studentDTO.getStudentNum());
                        } else {
                            studentSubmit.setStudentNum(studentDTO.getStudentNum().toString());
                        }
                        studentSubmit.setRawStudentNum(studentDTO.getStudentNum());
                        studentSubmit.setSubmitStatus(studentDTO.getSubmitStatus()); // 已提交
                        studentSubmit.setPaperImages(JSON.toJSONString(studentDTO.getPaperImages()));
                        studentSubmit.setExamDetailId(classInfo.getExamDetailId());
                        // 计算总分
                        double totalScore = studentDTO.getQuesInfos().stream()
                                .mapToDouble(ExamDetailDTO.QuestionScoreDTO::getScore)
                                .sum();
                        studentSubmit.setScore(totalScore);

                        studentSubmits.add(studentSubmit);
                    }

                    // 2. 批量插入学生提交记录，会自动回填ID
                    if (!studentSubmits.isEmpty()) {
                        studentSubmitMapper.insertBatch(studentSubmits);
                    }

                    // 3. 收集题目得分记录
                    for (int i = 0; i < examDetailDTO.getStudents().size(); i++) {
                        ExamDetailDTO.StudentDTO studentDTO = examDetailDTO.getStudents().get(i);
                        StudentSubmit studentSubmit = studentSubmits.get(i);  // 现在可以直接使用，因为ID已经回填

                        for (ExamDetailDTO.QuestionScoreDTO scoreDTO : studentDTO.getQuesInfos()) {
                            QuestionScore questionScore = new QuestionScore();
                            questionScore.setStudentSubmitId(studentSubmit.getId());
                            questionScore.setQuestionId(scoreDTO.getQuestionId());
                            questionScore.setScore(scoreDTO.getScore());
                            questionScore.setIsRight(scoreDTO.getIsRight());
                            questionScore.setExamDetailId(classInfo.getExamDetailId());
                            questionScore.setStudentAnswer(scoreDTO.getStudentAnswer());
                            allQuestionScores.add(questionScore);
                        }
                    }

                    // 4. 批量插入题目得分
                    if (!allQuestionScores.isEmpty()) {
                        questionScoreMapper.insertBatch(allQuestionScores);
                    }
                }

                log.info("获取成绩成功并保存: subjectId={}, classId={}", subjectId, classInfo.getClassId());
                if (!CollectionUtils.isEmpty(studentSubmits) && studentSubmits.size() != classInfo.getStudentSubmitCount()) {
                    //异常报警
                    log.error("获取成绩成功,但获取人数对不上 studnetSize={}, practical.studnetSize={}", classInfo.getStudentSubmitCount(), studentSubmits.size());
                }
                return studentSubmits;
            } else {
                log.error("获取成绩失败: status={}, response={}", response.getStatusCode(), response.getBody());
                throw new RuntimeException("成绩获取失败");
            }
        } catch (Exception e) {
            log.error("调用发布成绩接口失败: {}", e.getMessage(), e);
            throw new RuntimeException("调用发布成绩接口失败", e);
        }
    }

    public List<ExamBase> selectExamListByDate(LocalDate startTime, LocalDate endTime, Long subjectId, Long gradeId) {
        //先获取年级
        List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
        if (ObjectUtils.isEmpty(gradeInfoList)) {
            throw new RuntimeException("未找到年级信息");
        }
        List<Long> gradeIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
        List<ClassInfo> classInfoList = classInfoMapper.selectByGradeIds(gradeIds);
        List<Long> examDetailIds = classInfoList.stream().map(ClassInfo::getExamDetailId).collect(Collectors.toList());
        List<ExamDetail> examDetailList = examDetailMapper.selectListByExamDetailIds(examDetailIds);
        List<Long> examIds = examDetailList.stream().filter(e -> e.getSubjectOnlyid().equals(subjectId)).map(ExamDetail::getExamId).collect(Collectors.toList());
        List<ExamBase> examBaseList = examBaseMapper.selectByExamIdsAndDate(examIds, startTime, endTime);
        examBaseList.forEach(examBase -> {
            Long examDetailId = examDetailList.stream().filter(e -> e.getExamId().equals(examBase.getExamId())).collect(Collectors.toList()).get(0).getId();
            List<ClassInfo> classInfos = classInfoList.stream().filter(c -> c.getExamDetailId().equals(examDetailId)).collect(Collectors.toList());
            examBase.setClassInfoList(classInfos);
        });
        return examBaseList;
    }

    //发送消息提醒
    public void wxMessagePush(List<String> studentNumbers, String examName, Long examId, Long subjectId, String subjectName) throws Exception {
        ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
        if (examDetail == null) {
            return;
        }
        List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId());
        //获取本次成绩分析的所有学生的 openid
        String s = String.join(",", studentNumbers);
        String url = studentInfoUrl + "?studentNumbers=" + s;
        log.info("获取学生的url：" + url);
        // 发送 GET 请求
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        String result = response.getBody();

        if (response.getStatusCode() == HttpStatus.OK && result != null) {
            AjaxResult ajaxResult = JSON.parseObject(result, AjaxResult.class);
            if (!ajaxResult.get("code").toString().equals("200")) {
                log.info("发送模版消息请求oms返回信息：{}", ajaxResult);
                return;
            }
            String r = ajaxResult.get("data").toString();
            List<StudentInfo> studentInfos = JSON.parseArray(r, StudentInfo.class);
            //获取关注微信小程序的用户列表
            String accessToken = WxUtil.getAccessToken();
            if (accessToken == null) {
                return;
            }
            String openidStringList = WxUtil.getWxUserList(accessToken);
            List<String> openIds = JSON.parseArray(openidStringList, String.class);
            Map<String, String> userMap = new HashMap<>();
            for (int i = 0; i < openIds.size(); i++) {
                String userInfo = WxUtil.getUserInfo(accessToken, openIds.get(i));
                JSONObject wxUserInfo = JSON.parseObject(userInfo);
                userMap.put(wxUserInfo.getString("unionid"), wxUserInfo.getString("openid"));
            }
            if (!ObjectUtils.isEmpty(userMap)) {
                if (!ObjectUtils.isEmpty(studentInfos)) {
                    //先获取 微信公众号的token
                    for (StudentInfo studentInfo : studentInfos) {
                        if (ObjectUtils.isEmpty(studentInfo.getWxUnionId())) {
                            continue;
                        }
                        //通过学号获取学生的 studentId
                        List<StudentSubmit> student = submits.stream().filter(ss -> ss.getSubmitStatus() == 1 && ss.getStudentNum().equals(studentInfo.getStudentNumber())).collect(Collectors.toList());
                        if (!ObjectUtils.isEmpty(student)) {
                            Long studentId = student.get(0).getStudentId();
                            Long classId = student.get(0).getClassId();
                            String pagePath = String.format(wxPagePath + "examId=%s&studentId=%s&classId=%s&subjectId=%d&examDetailId=%s", examId, studentId, classId, subjectId, examName);
                            String openId = userMap.get(studentInfo.getWxUnionId());
                            //发送消息提醒
                            // 创建指定时间
                            LocalDateTime specificTime = LocalDateTime.now();
                            // 定义格式器
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm");
                            // 格式化时间
                            String formattedDateTime = specificTime.format(formatter);
                            WxUtil.sendTemplateMessage(accessToken, openId, studentInfo.getStudentName(), examName, pagePath, formattedDateTime, subjectName);
                        }
                    }
                }
            }
        }
    }


    /**
     * 构建错题数据
     *
     * @param param 作业
     */
    public void buildErrorQuestionData(ExamBaseDTO param) {
        //考试id
        Long examId = param.getExamId();
        log.info("开始构建错题数据...........考试id:{}", examId);
        ExamBase examBase = examBaseMapper.selectByExamId(examId);
        if (ObjectUtils.isEmpty(examBase)) {
            return;
        }
        //考试详情
        ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
        if (ObjectUtils.isEmpty(examDetail)) {
            return;
        }
        Long examDetailId = examDetail.getId();
        //学生的提交记录(只查询已提交的)
        List<StudentSubmit> studentSubmits = studentSubmitMapper.selectByExamDetailId(examDetailId);
        //提交id
        List<Long> submitIds = studentSubmits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(submitIds)) {
            log.info("examDetailId {} 没有提交记录，直接返回。", examDetailId);
        }
        //学生的错题(只查询已提交的)
        List<QuestionScore> questionScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
        if (CollectionUtils.isEmpty(questionScores)) {
            log.info("examDetailId {} 没有作答记录，直接返回。", examDetailId);
            return;
        }
        //作业的班级列表
        List<ClassInfo> classInfos = classInfoMapper.selectByExamDetailId(examDetailId);
        List<Long> classIds = classInfos.stream().map(ClassInfo::getClassOmsId).collect(Collectors.toList());
        //考试中的题列表
        List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetailId)
                //过滤questionUuid 为空的数据
                .stream().filter(e -> !ObjectUtils.isEmpty(e.getQuestionBankId())).collect(Collectors.toList());
        //年级详情
        List<GradeInfo> gradeInfos = gradeInfoMapper.selectByGradeId(examDetail.getGradeId());
        GradeInfo gradeInfo = gradeInfos.stream().filter(e -> !ObjectUtils.isEmpty(e.getGradeOmsId()))
                .findFirst().orElse(null);
        //构建错题消息体对象
        ErrorQuestionExamDTO errorQuestionExamDTO = buildMessageDate(questionInfos, questionScores, studentSubmits, classInfos, examId, examBase, gradeInfo, examDetail);
        try {
            //压缩数据 （这里需要压缩数据！ 因为线上kafka 消息体配置最大可接收1MB的数据，之前数据结构最大有7MB，优化数据结构为2.2MB,再压缩之后达到100KB以内）
            String message = GZipUtils.compressToBase64(JSON.toJSONString(errorQuestionExamDTO));
            int size = questionScores.size();
            ErrorQuestionKafkaMessageDTO errorQuestionKafkaMessageDTO = new ErrorQuestionKafkaMessageDTO()
                    .setClassIds(classIds)
                    .setSize(size)
                    .setExamId(examId)
                    .setErrorQuestionMessage(message);
            log.info("错题数据构建结束，一共 {} 道错题，准备发送到kafka...........", size);
            errorQuestionProducer.setToKafka(errorQuestionKafkaMessageDTO);
        } catch (IOException e) {
            log.error("压缩错题消息体异常: examId: {} ,message:{},", examId, e.getMessage());
            throw new RuntimeException(e);
        }

    }


    private ErrorQuestionExamDTO buildMessageDate(List<QuestionInfo> questionInfos, List<QuestionScore> questionScores, List<StudentSubmit> studentSubmits, List<ClassInfo> classInfos, Long examId, ExamBase examBase, GradeInfo gradeInfo, ExamDetail examDetail) {

        List<ErrorQuestionInfoDTO> errorQuestionInfos = questionInfos.stream().map(e -> {
            //考试平台自己的questionId
            Long questionId = e.getQuestionId();

            List<ErrorQuestionStudentScoreDTO> studentScoreDTOS = questionScores.stream().filter(qs -> qs.getQuestionId().equals(questionId))
                    .map(qs -> {
                        ErrorQuestionStudentScoreDTO studentScore = new ErrorQuestionStudentScoreDTO()
                                .setIsRight(qs.getIsRight())
                                .setStudentAnswer(qs.getStudentAnswer())
                                .setScore(qs.getScore());
                        Long studentSubmitId = qs.getStudentSubmitId();
                        ///根据学生提交记录set学生信息
                        studentSubmits.stream().filter(s -> s.getId().equals(studentSubmitId)).findAny()
                                .ifPresent(ifp -> {
                                    Long classInfoId = ifp.getClassInfoId();
                                    studentScore
                                            .setStudentNum(ifp.getRawStudentNum())
                                            .setStudentId(ifp.getStudentOmsId());
                                    classInfos.stream().filter(c -> c.getId().equals(classInfoId)).findAny()
                                            .ifPresent(classInfo ->
                                                    studentScore.setClassId(classInfo.getClassOmsId()));
                                });
                        return studentScore;
                    })
                    .collect(Collectors.toList());
            return new ErrorQuestionInfoDTO()
                    .setQuestionUuid(e.getQuestionBankId())
                    .setQuestionNum(e.getQuestionNum())
                    .setQuestionAlias(e.getQuestionAlias())
                    .setQuestionType(e.getQuestionType())
                    .setQuestionTypeName(e.getQuestionTypeName())
                    .setQuestionAnswer(e.getQuestionAnswer())
                    .setQuestionScore(e.getQuestionScore())
                    .setIsSubjectiveItem(e.getIsSubjectiveItem())
                    .setPage(e.getPage())
                    .setStudentScore(studentScoreDTOS);
        }).collect(Collectors.toList());
        //作业
        return new ErrorQuestionExamDTO()
                .setExamId(examId)
                .setExamName(examBase.getExamName())
                .setExamType(examBase.getExamType())
                .setGradeId(ObjectUtils.isEmpty(gradeInfo) ? null : gradeInfo.getGradeOmsId())
                .setGradeName(ObjectUtils.isEmpty(gradeInfo) ? null : gradeInfo.getGradeName())
                .setSubjectId(examDetail.getSubjectOnlyid())
                .setSubjectName(examDetail.getSubjectName())
                .setStageId(examBase.getStageOmsId())
                .setStage(examBase.getStage())
                .setSchoolId(examBase.getSchoolOmsId())
                .setStartTime(examBase.getStartTime())
                .setErrorQuestionInfo(errorQuestionInfos);
    }


}